package cn.pku.ss.sirx.sna.ib.db;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.List;
import org.hibernate.*;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.cfg.Configuration;

/**
 * To persistence objects.
 * 
 * @author SirX
 * @version 1.1
 */
public class PersistenceSystem {

	/**
	 * Get a PersistenceManager instance.
	 */
	public static PersistenceSystem getInstance() {
		if( instance==null ) {
			instance = new PersistenceSystem();
		}
		return instance;
	}
	
	/**
	 * Get a Session instance.
	 */
	public Session openSession() {
	    return this.sessionFactory.openSession();
	}
	
	/**
	 * Close a session.
	 */
	public void closeSession(Session session) {
	    if( session!=null ) {
	        try {
	            session.close();
	        } catch (HibernateException e) {
	            e.printStackTrace();
	        }
	    }
	}

	/**
	 * Save an object into database.
	 * @param obj an object to be saved
	 * @return the object id
	 * @throws SQLException when persistence exception happens
	 */
	public Serializable saveObject(Object obj) throws SQLException {
	    Session session = null;
	    Transaction tran = null;
	    try {
	        session = this.openSession();
	        tran = session.beginTransaction() ;
	        Serializable id = session.save(obj) ;
	        tran.commit() ;
	        return id;
        } catch (Exception e) {
            if( tran!=null ) {
                tran.rollback();
            }
            throw new SQLException(e);
        }
        finally {
            this.closeSession(session);
        }
	}
	
	/**
	 * Save a list of objects into database.
	 * @param objs a list of objects be saved
	 * @throws SQLException when persistence exception happens
	 */
	public void saveObjects(List<?> objs) throws SQLException {
	    Session session = null;
	    Transaction tran = null;
	    try {
	        session = this.openSession();
	        tran = session.beginTransaction() ;
	        for (Object object : objs) {
	            session.save(object) ;
            }
	        tran.commit() ;
	    } catch (Exception e) {
	        if( tran!=null ) {
	            tran.rollback();
	        }
            throw new SQLException(e);
	    }
	    finally {
	        this.closeSession(session);
	    }
	}
	
	/**
	 * load an object from database by its id.
	 * @param objClass object class
	 * @param objId	object id
	 * @return an object loaded from database; or null if not found
	 * @throws SQLException when persistence exception happens
	 */
	public Object loadObject(Class<?> objClass, Serializable objId) throws SQLException {
        Session session = null;
        Transaction tran = null;
        try {
            session = this.openSession();
            tran = session.beginTransaction();
            Object obj = session.get(objClass, objId);
            tran.commit();
            return obj;
        } catch (Exception e) {
            if (tran != null) {
                tran.rollback();
            }
            throw new SQLException(e);
        } finally {
            this.closeSession(session);
        }
    }
	
	/**
	 * Delete an object from database.
	 * @param obj an object to be deleted
	 * @throws SQLException when persistence exception happens
	 */
	public void deleteObject(Object obj) throws SQLException {
        Session session = null;
        Transaction tran = null;
        try {
            session = this.openSession();
            tran = session.beginTransaction() ;
            session.delete(obj);
            tran.commit() ;
        } catch (Exception e) {
            if( tran!=null ) {
                tran.rollback();
            }
            throw new SQLException(e);
        }
        finally {
            this.closeSession(session);
        }	    
	}
	
	/**
	 * Update an object in database.
	 * @param obj an object to be updated
	 * @throws SQLException when persistence exception happens
	 */
	public void updateObject(Object obj) throws SQLException {
        Session session = null;
        Transaction tran = null;
        try {
            session = this.openSession();
            tran = session.beginTransaction() ;
            session.update(obj);
            tran.commit() ;
        } catch (Exception e) {
            if( tran!=null ) {
                tran.rollback();
            }
            throw new SQLException(e);
        }
        finally {
            this.closeSession(session);
        }
	}
	
//	public void executeJDBC(String command) throws SQLException {
//        Session session = null;
//        Transaction tran = null;
//        try {
//            session = this.openSession();
//            tran = session.beginTransaction() ;
//            session.connection().prepareStatement(command).execute();
//            tran.commit() ;
//        } catch (Exception e) {
//            if( tran!=null ) {
//                tran.rollback();
//            }
//            throw new SQLException(e);
//        }
//        finally {
//            this.closeSession(session);
//        }
//	}
	
	//////////////////////////////////////////////////////////////////////////////

	private PersistenceSystem() {
	    try {
	        Configuration cfg = new AnnotationConfiguration();
	        this.sessionFactory = cfg.configure().buildSessionFactory();
        } catch (Exception e) {
        	throw new RuntimeException(e);
        }
	}
	
	//////////////////////////////////////////////////////////////////////////////
	
	private static PersistenceSystem instance;

	private SessionFactory sessionFactory;
	
}
